#pragma once

#include <iostream>
#include <string>
#include <cstring>
#include <sys/poll.h>
#include "Sock.hpp"
#include "Log.hpp"

using namespace std;
const static int gport = 8080;
typedef struct pollfd type_t;
const static int N = 4096;
const static short defaultEvent = 0;

class PollServer{

public:
    PollServer(uint16_t port = gport):port_(port), fdArray_(nullptr){

    }

    void InitServer(){
        listenSock_.Socket();
        listenSock_.Bind(port_);
        listenSock_.Listen();
        fdArray_ = new type_t[N];

        for(int i = 0; i < N; i++){
            fdArray_[i].fd = defaultSock;
            fdArray_[i].events = defaultEvent;
            fdArray_[i].revents = defaultEvent;
        }
    }

    void Accepter(){
        string clientIp;
        uint16_t clientPort;
        int sock = listenSock_.Accept(&clientIp, &clientPort);
        if(sock < 0)
            return;
        //得到了sock, 先不进行read/recv, 因为sock上不一定有数据就绪
        //将sock交给select, 让select进行管理
        logMessage(Debug, "[%s: %d], sock: %d", clientIp.c_str(), clientPort, sock);
        int pos = 1;
        for(; pos < N; pos++){
            if(fdArray_[pos].fd == defaultSock)
                break;
        }
        if(pos >= N){
            //可以考虑动态扩容
            close(sock);
            logMessage(Warning, "sockfd array full");
        }
        else
            fdArray_[pos].fd = sock;
            fdArray_[pos].events = POLLIN;
            fdArray_[pos].revents = defaultEvent;
    }

    void HandlerEvent(){
        for(int i = 0; i < N; i++){
            int fd = fdArray_[i].fd;
            short revent = fdArray_[i].revents;

            if(fd == defaultSock)
                continue;

            if((fd == listenSock_.GetSock()) && (revent & POLLIN))
                Accepter();

            else if(fd != listenSock_.GetSock() && (revent & POLLIN)){
                //ServerceIO()
                char buffer[1024];
                ssize_t s = recv(fd, buffer, sizeof(buffer)-1, 0);
                if(s > 0){
                    buffer[s-1] = 0;
                    cout << "client# " << buffer << endl;
                    string echo = buffer;
                    echo += "[selectServer echo]";
                    send(fd, echo.c_str(), echo.size(), 0);
                }
                else{
                    if(s == 0)
                        logMessage(Info, "client quit ..., fdarray_[i] -> defaultfd: %d->%d", fd, defaultSock);
                    else
                        logMessage(Warning, "recv error, client quit ..., fdarray_[i] -> defaultfd: %d->%d", fd, defaultSock);
                    close(fd);
                    fdArray_[i].fd = defaultSock;
                    fdArray_[i].events = defaultEvent;
                    fdArray_[i].revents = defaultEvent;
                }
            }
        }
    }

    void Start(){
        fdArray_[0].fd = listenSock_.GetSock();
        fdArray_[0].events = POLLIN;

        while(true){
            int timeout = -1;
            int n = poll(fdArray_, N, timeout);
            switch(n){
                case 0:
                    logMessage(Debug, "timeout, %d: %s", errno, strerror(errno));
                    break;
                case -1:
                    logMessage(Warning, "%d: %s", errno, strerror(errno));
                    break;
                default:
                    logMessage(Debug, "happen: %d", n);
                    HandlerEvent();
                    DebugPrint();
                    break;
            }
            sleep(1);
        }
    }

    void DebugPrint(){
        cout << "fdArray[]: ";
        for(int i = 0; i < N; i++){
            if(fdArray_[i].fd == defaultSock)
                continue;
            cout << fdArray_[i].fd << " ";
        }
        cout << endl;
    }

    ~PollServer(){
        listenSock_.Close();
        if(fdArray_)
            delete[] fdArray_;
    }

private:
    uint16_t port_;
    Sock listenSock_;
    type_t* fdArray_;
};